package com.hdy.web.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.hdy.web.Annotation.Val;
import com.hdy.web.constant.AfterSaleStatus;
import com.hdy.web.constant.ResponseCode;
import com.hdy.web.dao.SkuInfoDao;
import com.hdy.web.exception.CalculateException;
import com.hdy.web.handler.CustomCellWriteHandler;
import com.hdy.web.listener.OrderInfoListener;
import com.hdy.web.pojo.OrderInfo;
import com.hdy.web.pojo.ProfitData;
import com.hdy.web.pojo.SkuInfo;
import com.hdy.web.pojo.TotalExpenses;
import com.hdy.web.utils.EasyExcelUtil;
import com.hdy.web.utils.StringToNumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReadExcel {
    @Resource
    SkuInfoDao skuInfoDao;
    public static BigDecimal chargeRatio = new BigDecimal("0.05");
    public static BigDecimal commissionRatio = new BigDecimal("0.2");

    public boolean calculate(MultipartFile file, boolean is_return_commission, Integer insurance,HttpServletRequest request) throws CalculateException {
        EasyExcelUtil<OrderInfo> easyExcelUtil = new EasyExcelUtil<>();
        long start = System.currentTimeMillis();
        List<OrderInfo> maps;//
        OrderInfoListener listener = new OrderInfoListener();
        try {
            easyExcelUtil.asyncRead(transferToFile(file), listener, 0, 1);
        } catch (Exception e) {
            e.printStackTrace();
            throw new CalculateException(ResponseCode.ORDER_FORMAT_ERROR, "Excel读取失败！");
        }
        Field[] declaredFields = OrderInfo.class.getDeclaredFields();
        Map<Integer, String> headerMap = listener.getOrderInfoHeaderMap();
        for (Field field : declaredFields) {
            Val annotation = field.getAnnotation(Val.class);
            if (!annotation.val().equals(headerMap.get(annotation.index()))) {
                throw new CalculateException(ResponseCode.ORDER_FORMAT_ERROR, "订单格式有误！");
            }
        }
        maps = listener.getOrderInfoMap();
        ArrayList<ProfitData> list = new ArrayList<>();
        List<SkuInfo> all;
        try {
            all = skuInfoDao.getAll();
        } catch (Exception e) {
            throw new CalculateException(ResponseCode.ERROR, "读取商品信息失败！");
        }
        HashMap<String, SkuInfo> map = new HashMap<>();
        for (SkuInfo sku : all) {
            map.put(sku.getCommodityNumber() + sku.getSellingPrice(), sku);
            map.put(sku.getCommodityNumber(), sku);
        }
        //前置筛选重复订单
        List<List<OrderInfo>> tempList = maps.stream().collect(Collectors.groupingBy(OrderInfo::getOrderNo)).values().stream().filter(orderInfos -> orderInfos.size() > 1).toList();
        //存在重复订单
        if (tempList.size() > 0) {
            for (List<OrderInfo> lists : tempList) {
                OrderInfo order = lists.get(0);
                if (order.getDate()!=null&&!order.getDate().equals("")) {
                    //获取备注
                    String remark = order.getRemark() == null ? "test" : order.getRemark();
                    //含数字
                    if (StringToNumberUtil.isNum(remark) && !remark.contains("+") && !remark.contains("-")) {
                        //计算总销售额
                        BigDecimal total = new BigDecimal("0");
                        for (OrderInfo info : lists) {
                            String afterSale = info.getAfterSale();
                            if (!afterSale.contains(AfterSaleStatus.Refund_Successful) && !afterSale.contains(AfterSaleStatus.Waiting_For_Return) && !afterSale.contains(AfterSaleStatus.Waiting_For_Receipt_And_Return)) {
                                total = total.add(new BigDecimal(info.getPrice()));
                            }
                        }
                        order.setPrice(total.toString());
                        maps.removeIf(orderInfo -> Objects.equals(orderInfo.getOrderNo(), order.getOrderNo()));
                        maps.add(order);
                    } else {
                        //不合并，减去多扣的运费险和售后预估
                        for (int i = 0; i < lists.size() - 1; i++) {
                            if (lists.get(i).getStatus().equals("已发货") || lists.get(i).getStatus().equals("待发货")) {
                                lists.get(i).setRemark("-13");
                            } else {
                                lists.get(i).setRemark("-3");
                            }
                        }
                    }
                }
            }
        }
        for (OrderInfo order : maps) {
            //首先判断有无支付时间，无则下一个订单
            if (order.getDate() == null) continue;
            //利润表信息
            ProfitData profitData = new ProfitData();
            //获得商品数量
            int quantity = Integer.parseInt(order.getQuantity());
            //获得成本
            BigDecimal cost = new BigDecimal("0");
            //额外运费
            BigDecimal extra = new BigDecimal("0");
            //订单售价
            String orderPrice = order.getPrice();
            //旗帜颜色
            String color = order.getColor();
            //订单状态
            String status = order.getStatus();
            //预估费用
            int estimated = 0;
            //商品成本信息
            SkuInfo skuInfo = null;
            //商品ID
            String commodityID = order.getCommodityID();
            List<String> commodityList = Arrays.stream(commodityID.split(";")).toList();
            commodityID = commodityList.get(0);

            //判断旗帜颜色
            if (color.equals("蓝色")) {
                cost = BigDecimal.valueOf(Double.parseDouble(orderPrice) + 2);
            } else if (color.equals("红色")) {
                estimated = 10;
                profitData.setInsurance(0);
            } else {
                //先判断有无备注，有备注，取备注中的成本
                //防止备注为空
                String remark = order.getRemark() == null ? "test" : order.getRemark();
                String result = StringToNumberUtil.convert(remark);
                if (!result.equals("")) {
                    BigDecimal num = BigDecimal.valueOf(Double.parseDouble(result));
                    //如果有‘+’，则有额外运费
                    if (order.getRemark().contains("+")) extra = num;
                        //如果有‘-’，则成本减钱
                    else if (order.getRemark().contains("-")) extra = BigDecimal.ZERO.subtract(num);
                    else cost = num.divide(BigDecimal.valueOf(quantity), RoundingMode.CEILING);
                }

                //计算没有成本备注，没有运费，的成本
                if (result.equals("") || extra.compareTo(BigDecimal.ZERO) != 0) {
                    //获得商品成本信息
                    double price = Double.parseDouble(orderPrice);
                    skuInfo = map.get(commodityID + price);
                    if (skuInfo == null) {
                        skuInfo = map.get(commodityID);
                        if (skuInfo == null) {
                            throw new CalculateException(99, "有未查到成本信息的商品，请及时更新成本信息！\n订单详情:\n订单编号:" + order.getOrderNo() + "\n商品ID:" + order.getCommodityID() + "\n商品名称:" + order.getName());
                        }
                    }
                    //计算出成本
                    cost = BigDecimal.valueOf(skuInfo.getCostPrice());
                }
                //获得售后状态
                String afterSale = order.getAfterSale();
                //不存在售后
                if (afterSale.equals("-")) {
                    if (status.equals("已发货") || status.equals("待发货"))
                        estimated = quantity * 10;
                } else {
                    //存在售后
                    List<String> strings;
                    //获得售后情况的list
                    strings = Arrays.stream(afterSale.split(";")).toList();
                    //获得每一个售后情况
                    for (String s : strings) {
                        String string = s.substring(s.indexOf("-") + 1);
                        if (string.equals(AfterSaleStatus.Refund_Successful) || string.equals(AfterSaleStatus.Waiting_For_Receipt_And_Return) || string.equals(AfterSaleStatus.Waiting_For_Return)) {
                            quantity--;
                        } else if (string.equals(AfterSaleStatus.Successful_Replacement_Of_Goods) || string.equals(AfterSaleStatus.Return_And_Waiting_For_Goods)) {
                            extra = extra.add(BigDecimal.TEN);
                        }
                    }
                    //退了几双就是几双的售后费用
                    if (!color.equals("灰色")) estimated = (Integer.parseInt(order.getQuantity()) - quantity) * 10;
                    else profitData.setInsurance(0);
                }
                //单价成本乘以数量
                cost = cost.multiply(BigDecimal.valueOf(quantity));
                //加上运费
                cost = cost.add(extra);
            }
            if (insurance!=null) profitData.setInsurance(insurance);
            profitData.setDate(order.getDate());
            profitData.setOrderNo(order.getOrderNo());
            new BigDecimal(0);

            //skuInfo为null的情况有：1. 刷单，不需要查看成本价
            //2.已发货，拦截退款，也不查
            //3. 备注成本，也不查
            if (quantity < 1) {
                profitData.setTransactionAmount(BigDecimal.ZERO);
            } else {
                if (skuInfo == null) {
                    if (color.equals("红色"))
                        profitData.setTransactionAmount(BigDecimal.ZERO);//旗帜为红色
                    else
                        profitData.setTransactionAmount(new BigDecimal(orderPrice));
                } else {
                    BigDecimal total = new BigDecimal(skuInfo.getSellingPrice() * quantity);
                    profitData.setTransactionAmount(total);
                }
            }
            //是否返佣活动
            if (is_return_commission) {
                profitData.setReturn_Commission(profitData.getTransactionAmount().multiply(new BigDecimal("0.044")));
            } else {
                profitData.setReturn_Commission(BigDecimal.ZERO);
            }
            //是否达人佣金
            if (!order.getCellularSource().contains("小店自卖"))
                profitData.setCommission(profitData.getTransactionAmount().multiply(commissionRatio));
            else profitData.setCommission(BigDecimal.ZERO);
            profitData.setCharge(profitData.getTransactionAmount().multiply(chargeRatio).setScale(4, RoundingMode.FLOOR));
            profitData.setEstimatedCost(estimated);
            profitData.setCost(cost);
            profitData.calculateProfit();
            profitData.setTotalProfit(profitData.getProfit().add(profitData.getReturn_Commission()));
            list.add(profitData);
        }
        ArrayList<ProfitData> result = new ArrayList<>();
        ArrayList<TotalExpenses> result2 = new ArrayList<>();
        list.stream().collect(Collectors
                        .groupingBy(ProfitData::getDate))
                .entrySet().stream()
                .sorted(Map.Entry.<String, List<ProfitData>>comparingByKey().reversed())
                .forEach(((entry) -> {
                    List<ProfitData> group = entry.getValue();
                    result.addAll(group);
                    ProfitData data = new ProfitData();
                    data.setInsurance(null);
                    result.add(data);
                    TotalExpenses totalExpenses = new TotalExpenses();
                    totalExpenses.setDate(entry.getKey());
                    totalExpenses.setProfit(group.stream().map(ProfitData::getProfit).reduce(BigDecimal.ZERO, BigDecimal::add));
                    totalExpenses.setReturnFunds(group.stream().map(ProfitData::getReturn_Commission).reduce(BigDecimal.ZERO, BigDecimal::add));
                    totalExpenses.setTotalProfit(group.stream().map(ProfitData::getTotalProfit).reduce(BigDecimal.ZERO, BigDecimal::add));
                    totalExpenses.setSalesAmount(group.stream().map(ProfitData::getTransactionAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
                    result2.add(totalExpenses);
                }));
        CustomCellWriteHandler customCellWriteHandler = new CustomCellWriteHandler();
        log.info(System.getProperty("user.dir") + File.separator + request.getSession().getAttribute("userName") + ".xlsx");
        try (ExcelWriter writerBuilder = EasyExcel.write(System.getProperty("user.dir") + File.separator + request.getSession().getAttribute("userName") + ".xlsx").build()) {
            WriteSheet sheet1 = EasyExcel.writerSheet("利润表").head(ProfitData.class).registerWriteHandler(customCellWriteHandler).build();
            writerBuilder.write(result, sheet1);
            WriteSheet sheet2 = EasyExcel.writerSheet("日汇总").head(TotalExpenses.class).registerWriteHandler(customCellWriteHandler).build();
            writerBuilder.write(result2, sheet2);
            writerBuilder.finish();
        }
        //EasyExcel.write(expFilePath, ProfitData.class).needHead(true).sheet().doWrite(result);//F:\Store\a表格\profit2.xlsx
        long end = System.currentTimeMillis();
        log.info(end - start + "ms");
        return true;
    }

    public File transferToFile(MultipartFile multipartFile) {
//        选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferTo()方法 。
        File file = null;
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String[] filename = originalFilename.split("\\.");
            StringBuilder prefix = new StringBuilder();
            for (int i = 0; i < filename.length - 1; i++) {
                prefix.append(filename[i]);
            }
            prefix.append("file");
            file = File.createTempFile(prefix.toString(), filename[filename.length - 1]);
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }
}
